package service

import (
	"cgs-server/server"
	"cgs-server/server/cgs/app/models"
	"cgs-server/server/cgs/app/models/dto"
	v1 "cgs-server/server/cgs/app/models/v1"
	"cgs-server/server/cgs/app/models/vo"
	"cgs-server/server/cgs/app/store"
	"cgs-server/server/model"
	"errors"
	"go.mongodb.org/mongo-driver/bson/primitive"
)

type WorksheetGroupSrv interface {
	ListByAppId(appId string, user *model.User) (*vo.WorksheetGroupList, error)
	Detail(groupId string, user *model.User) (*vo.WorksheetGroup, error)
	Delete(groupId string, newGroupId string, user *model.User) error
	Save(wg *models.WorksheetGroup, user *model.User) error
	Update(wg *dto.WorksheetGroup, user *model.User) error
}

type worksheetGroupSrv struct {
	store store.Factory
}

func (w *worksheetGroupSrv) Update(wg *dto.WorksheetGroup, user *model.User) error {
	// 处理worksheetInfoIds
	group, err := w.Detail(wg.Id.Hex(), user)
	if err != nil {
		return err
	}

	if wg.WorksheetInfoIds != nil {
		//if group.WorksheetInfoIds != nil {
		//
		//} else {
		//	// 2. 查询表单列表
		//	wsInfoOptions := v1.ListOptions{}
		//	wsInfoOptions.AddFilter("groupId", wg.GetId())
		//	infoList, err := w.store.WorksheetInfo().List(&models.WorksheetInfo{}, user, wsInfoOptions)
		//	if err != nil {
		//		return err
		//	}
		//	ids := []string{}
		//	for _, info := range *infoList {
		//		if info.Hidden {
		//			ids = append(ids, info.Id.Hex())
		//		}
		//	}
		//
		//}

		// 暂时只允许管理员排序
		_, err = getAppAuths(group.AppId, user)
		if err != nil {
			return err
		}
		if !user.HasAuth(group.AppId, server.ManageAppAuth) {
			return nil
		}
	}

	err = w.store.WorksheetGroup().Update(wg, user, v1.UpdateOptions{})
	return err
}

func (w *worksheetGroupSrv) Save(wg *models.WorksheetGroup, user *model.User) error {
	err := w.store.WorksheetGroup().Save(wg, user, v1.CreateOptions{})
	if err != nil {
		return err
	}

	// 更新 app 中的分组顺序
	appObjId, err := primitive.ObjectIDFromHex(wg.AppId)
	if err != nil {
		return err
	}
	app, err := w.store.App().Get(&models.App{Id: appObjId}, user, v1.GetOptions{})
	if err != nil {
		return err
	}
	if app.WorksheetGroupIds != nil {
		*app.WorksheetGroupIds = append(*app.WorksheetGroupIds, wg.GetId())
		err = w.store.App().Update(&dto.App{
			Id:                appObjId,
			WorksheetGroupIds: app.WorksheetGroupIds,
		}, user, v1.UpdateOptions{})
		if err != nil {
			return err
		}
	}

	return nil
}

func (w *worksheetGroupSrv) Delete(groupId string, newGroupId string, user *model.User) error {
	// 1.更新当前分组下的表单，移动到新分组
	// 2. 查询表单列表
	wsInfoListOptions := v1.ListOptions{}
	wsInfoListOptions.AddFilter("groupId", groupId)
	infoList, err := w.store.WorksheetInfo().List(&models.WorksheetInfo{}, user, wsInfoListOptions)
	if err != nil {
		return err
	}
	// 当前分组下存在表单，但是没传新的分组id，返回错误
	if len(*infoList) > 0 && newGroupId == "" {
		return errors.New("newGroupId is required, because there are some worksheetInfos in current group")
	}

	groupObjId, err := primitive.ObjectIDFromHex(groupId)
	if err != nil {
		return err
	}
	wsInfoOptions := v1.UpdateOptions{}
	wsInfoOptions.AddFilter("groupId", groupId)
	wsInfo := &models.WorksheetInfo{GroupId: newGroupId}
	err = w.store.WorksheetInfo().UpdateMany(wsInfo, user, wsInfoOptions)
	if err != nil {
		return err
	}

	// 2. 更新新分组的表单排序
	group, err := w.store.WorksheetGroup().Get(&models.WorksheetGroup{Id: groupObjId}, user, v1.GetOptions{})
	if err != nil {
		return err
	}
	if group.WorksheetInfoIds != nil && len(*group.WorksheetInfoIds) > 0 {
		newGroupObjId, err := primitive.ObjectIDFromHex(newGroupId)
		if err != nil {
			return err
		}
		newGroup, err := w.store.WorksheetGroup().Get(&models.WorksheetGroup{Id: newGroupObjId}, user, v1.GetOptions{})
		if err != nil {
			return err
		}
		if newGroup.WorksheetInfoIds == nil {
			// 是空的话直接复制
			newGroup.WorksheetInfoIds = group.WorksheetInfoIds
		} else {
			// 否则添加到末尾
			*newGroup.WorksheetInfoIds = append(*newGroup.WorksheetInfoIds, *group.WorksheetInfoIds...)
		}
		err = w.Update(&dto.WorksheetGroup{
			Id:               newGroupObjId,
			WorksheetInfoIds: newGroup.WorksheetInfoIds,
		}, user)
		if err != nil {
			return err
		}
	}

	// 3. 删除分组
	err = w.store.WorksheetGroup().Delete(&models.WorksheetGroup{Id: groupObjId}, user, v1.DeleteOptions{})
	return err
}

func (w *worksheetGroupSrv) Detail(groupId string, user *model.User) (*vo.WorksheetGroup, error) {
	// 1. 查询分组信息
	groupObjId, err := primitive.ObjectIDFromHex(groupId)
	if err != nil {
		return nil, err
	}
	wg := models.WorksheetGroup{Id: groupObjId}
	worksheetGroup, err := w.store.WorksheetGroup().Get(&wg, user, v1.GetOptions{})
	if err != nil {
		return nil, err
	}
	// 2. 查询表单列表
	wsInfoOptions := v1.ListOptions{}
	wsInfoOptions.AddFilter("groupId", groupId)
	infoList, err := w.store.WorksheetInfo().List(&models.WorksheetInfo{}, user, wsInfoOptions)
	if err != nil {
		return nil, err
	}

	_, err = getAppAuths(worksheetGroup.AppId, user)
	if err != nil {
		return nil, err
	}
	newInfoList := vo.WorksheetInfoList{}
	for _, s := range *infoList {
		// 权限控制
		if s.Hidden && !user.HasAuth(worksheetGroup.AppId, server.ManageAppAuth) {
			continue
		}
		if !user.HasFormAuth(worksheetGroup.AppId, s.Id.Hex(), server.FormRead) {
			continue
		}

		newInfoList = append(newInfoList, s)
	}
	worksheetGroup.WorksheetInfoList = &newInfoList

	//worksheetGroup.WorksheetInfoList = infoList

	// 3. 排序
	if worksheetGroup.WorksheetInfoIds != nil && len(*worksheetGroup.WorksheetInfoIds) > 0 {
		appMap := make(map[string]*vo.WorksheetInfo, len(newInfoList))
		for _, wsInfo := range newInfoList {
			appMap[wsInfo.Id.Hex()] = wsInfo
		}

		nInfoList := vo.WorksheetInfoList{}
		for _, s := range *worksheetGroup.WorksheetInfoIds {
			if g, ok := appMap[s]; ok {
				nInfoList = append(nInfoList, g)
			}
		}
		worksheetGroup.WorksheetInfoList = &nInfoList
	}

	return worksheetGroup, err
}

func (w *worksheetGroupSrv) ListByAppId(appId string, user *model.User) (*vo.WorksheetGroupList, error) {
	wg := models.WorksheetGroup{}
	opts := v1.ListOptions{}
	opts.AddFilter("appId", appId)
	list, err := w.store.WorksheetGroup().List(&wg, user, opts)
	return list, err
}

func newWorksheetGroupSrv(s *service) WorksheetGroupSrv {
	return &worksheetGroupSrv{
		store: s.store,
	}
}
